#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include <arpa/inet.h>

#define Convert(addr) ((struct sockaddr *)addr)

namespace Net_Work
{
    const static int defaultsockfd = -1;
    const static int backlog = 5;
    enum
    {
        SocketError = 1,
        BindError,
        ListenError,
    };
    class Socket
    {
    public:
        virtual ~Socket() {}
        virtual void CreateSocketOrDie() = 0;
        virtual void BindSocketOrDie(uint16_t port) = 0;
        virtual void ListenSocketOrDie(int backlog) = 0;
        virtual Socket *AcceptConnection(std::string *peerip,uint16_t *peerport) = 0;
        virtual bool ConnectServer(std::string &serverip, uint16_t serverport) = 0;
        virtual int GetSockFd() = 0;
        virtual void SetSockFd(int sockfd) = 0;
        virtual void CloseSocket() = 0;
        virtual bool Recv(std::string *buffer) = 0;
        virtual void Send(std::string &send_str) = 0;

        public:
        void BuildListenSocketMethod(uint16_t port,int backlog)
        {
            CreateSocketOrDie();
            BindSocketOrDie(port);
            ListenSocketOrDie(backlog);
        }
        bool BuildConnectSocketMethod(std::string &serverip,uint16_t serverport)
        {
            CreateSocketOrDie();
            ConnectServer(serverip,serverport);
            return true;
        }
        void BuildNormalSocketMethod(int sockfd)
        {
            SetSockFd(sockfd);
        }
    };
    
    class TcpSocket:public Socket
    {
        public:
        TcpSocket(int sockfd=defaultsockfd):_sockfd(sockfd){}
        ~TcpSocket()
        {
            close(_sockfd);
        }

        virtual void CreateSocketOrDie() override
        {
            _sockfd=socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                std::cout<<"创建socket失败"<<std::endl;
                exit(SocketError);
            }
        }

        virtual void BindSocketOrDie(uint16_t port) override
        {
            struct sockaddr_in addr;
            memset(&addr,0,sizeof(addr));
            addr.sin_addr.s_addr=INADDR_ANY;
            addr.sin_family=AF_INET;
            addr.sin_port=htons(port);
            int opt=1;
            setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR |SO_REUSEPORT, &opt, sizeof(opt));
            int n=bind(_sockfd,Convert(&addr),sizeof(addr));
            if(n<0)
            {
                std::cout<<"bind失败"<<std::endl;
                exit(BindError);
            }
        }

        virtual void ListenSocketOrDie(int backlog) override
        {
            int n=listen(_sockfd,backlog);
            if(n<0)
            {
                std::cout<<"listen失败"<<std::endl;
                exit(ListenError);
            }
        }

        virtual Socket *AcceptConnection(std::string *peerip,uint16_t *peerport) override
        {
            struct sockaddr_in addr;
            socklen_t len=sizeof(addr);
            int sockfd=accept(_sockfd,Convert(&addr),&len);
            if(sockfd<0)
            {
                std::cout<<"accept error,"<<errno<<":"<<strerror(errno)<<std::endl;
                return nullptr;
            }
            *peerip=inet_ntoa(addr.sin_addr);
            *peerport=ntohs(addr.sin_port);
            return new TcpSocket(sockfd);
        }

        virtual bool ConnectServer(std::string &serverip, uint16_t serverport) override
        {
            struct sockaddr_in addr;
            memset(&addr,0,sizeof(addr));
            addr.sin_addr.s_addr=inet_addr(serverip.c_str());
            addr.sin_family=AF_INET;
            addr.sin_port=htons(serverport);
            int n=connect(_sockfd,Convert(&addr),sizeof(addr));
            if(n==0)
                return true;
            return false;
        }

        virtual int GetSockFd() override
        {
            return _sockfd;
        }

        virtual void SetSockFd(int sockfd) override
        {
            _sockfd=sockfd;
        }
        
        virtual void CloseSocket() override
        {
            if(_sockfd>defaultsockfd)
                close(_sockfd);
        }

        virtual bool Recv(std::string *buffer) override
        {
            char inbuffer[1024];
            int n=recv(_sockfd,inbuffer,sizeof(inbuffer)-1,0);
            if(n>0)
            {
                inbuffer[n]=0;
                *buffer+=inbuffer;
                return true;
            }
            return false;
        }

        virtual void Send(std::string &send_str) override
        {
            send(_sockfd,send_str.c_str(),send_str.size(),0);
        }
        private:
        int _sockfd;
    };
};